package dwarffortess.web.research;

import dwarffortress.loaders.DFWorldDatLoader;
import dwarffortress.loaders.StrongAssumptionException;
import dwarffortress.data.DFWorld;
import dwarffortress.data.DFEntity;
import dwarffortress.io.StrangeSizeException;
import dwarffortress.tools.Logger;
import dwarffortress.analysis.StructureAnalyzer;
import dwarffortress.analysis.ObjectAnalyzer;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.*;

public class ResearchThread extends Thread {
    private MainFrame frame;
    private Logger log;
    private File[] worldDirs;

    public ResearchThread(MainFrame frame, Logger log, File[] worldDirs) {
        this.frame = frame;
        this.log = new AWTLoggerAdapter(log);
        this.worldDirs = worldDirs;
    }

    public void run()  {

        try {
            StructureAnalyzer<DFEntity> entityStructure = new StructureAnalyzer<DFEntity>(DFEntity.class);
            TreeMap<Integer, Set<Integer>> map = new TreeMap<Integer, Set<Integer>>();
            for (int i = 0; i < entityStructure.getFieldCount(); i++) {
                map.put(i, new TreeSet<Integer>());
            }

            int field = 006;

            for (File worldDir : worldDirs) {
                log.log(Logger.TEXT, String.format("World %s", worldDir.getName()));
                try {
                    DFWorld world = DFWorldDatLoader.loadDFWorld(worldDir, log);

                    for (DFEntity e : world.entities) {
                        ObjectAnalyzer<DFEntity> analyzer = entityStructure.analyze(e);
//                        for (int i = 0; i < entityStructure.getFieldCount(); i++) {
//                            if (entityStructure.getField(i).getType().isPrimitive()) {
//                                map.get(i).add(analyzer.getIntValue(i));
//                            }
//                        }

                        log.log(Logger.TEXT, String.format("ID %3d Kind %d Type %8s Ref%3d ", e.f001_id, e.f000_kind, e.f002_typeRef, analyzer.getIntValue(field)));
                    }
                    log.log(Logger.TEXT, "Loaded normally");
                } catch (StrongAssumptionException e) {
                    log.log(Logger.CRITICAL_ASSUMPTIONS, e.getMessage());
                } catch (StrangeSizeException e) {
                    log.log(Logger.CRITICAL_ASSUMPTIONS, e.getMessage());
                } catch (IOException e) {
                    log.log(Logger.ERROR, "I/O problem while reading world : " + e.getMessage());
                    StringWriter writer = new StringWriter();
                    e.printStackTrace(new PrintWriter(writer));
                    log.log(Logger.ERROR, writer.toString());
                }
            }

//            for (int i = 0; i < entityStructure.getFieldCount(); i++) {
//                if (entityStructure.getField(i).getType().isPrimitive()) {
//                    Set<Integer> integers = map.get(i);
//                    if (integers.size() < 5) {
//                        log.log(Logger.TEXT, "Field " + entityStructure.getField(i).getName() + " : " + integers.toString());
//                    }
//                }
//            }


            log.log(Logger.TEXT, "Research complete");
        } catch (Exception e) {
            log.log(Logger.ERROR, "Some big problem during research : " + e.getMessage());
            StringWriter writer = new StringWriter();
            e.printStackTrace(new PrintWriter(writer));
            log.log(Logger.ERROR, writer.toString());
        } finally {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    frame.researchFinished();
                }
            });

        }

    }

    private static class AWTLoggerAdapter implements Logger {
        Logger log;

        public AWTLoggerAdapter(Logger log) {
            this.log = log;
        }

        public void log(final int level, final String message) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    log.log(level, message);
                }
            });
        }
    }

}
